How Do Python Functions Handle the Types of Parameters That You Pass In

How do Python functions handle the types of parameters that you pass in?

Python is strongly typed because every object has a type, every object knows its type, it's impossible to accidentally or deliberately use an object of a type "as if" it was an object of a different type, and all elementary operations on the object are delegated to its type.

This has nothing to do with names. A name in Python doesn't "have a type": if and when a name's defined, the name refers to an object, and the object does have a type (but that doesn't in fact force a type on the name: a name is a name).

A name in Python can perfectly well refer to different objects at different times (as in most programming languages, though not all) -- and there is no constraint on the name such that, if it has once referred to an object of type X, it's then forevermore constrained to refer only to other objects of type X. Constraints on names are not part of the concept of "strong typing", though some enthusiasts of static typing (where names do get constrained, and in a static, AKA compile-time, fashion, too) do misuse the term this way.

Call Python function passed as parameter without knowing if it takes any parameters

The preferred method of handling this is probably along these lines:

def doCommand(function, *args, **kwargs):
# do a thing
function(*args, **kwargs)
# do a thing

*args and **kwargs allow arbitrary arguments to be passed along to a method. As the name implies, these allow you to call doCommand with an arbitrary number of arguments and keyword arguments as well that get passed onto function.

Python best practice: How to handle function parameters that can be 2 types?

Don't. Make __init__ expect a DataFrame, and make the caller responsible (perhaps via a class method) for converting a string to a DataFrame before DataPipeline.__init__ is called.

class DataPipeline:

def __init__(self, data: DataFrame):
self.df = df

@classmethod
def from_string(cls, data: str):
return cls(spark.read.table(data))

p1 = DataPipeline(some_data_frame)
p2 = DataPipeline.from_string("...") # DataPipline(spark.read.table("..."))

Ryan Singer (supposedly; for as often as it is quoted, I've yet to find the original source) once said

So much complexity in software comes from trying to make one thing do two things.

Here, you are trying to make one thing (DataPipeline.__init__) to two things (initialize a DataPipeline using a string, and initialize a DataPipeline with a DataFrame).

For the refactoring, I chose to make the simplest case (accepting a DataFrame) for __init__, with the more complex logic of first parsing a string into a DataFrame moved into a separate class method that calls __init__ with an appropriate data frame.


(Whether you want to make any explicit runtime checks for type validation to fail early, or just assume that the caller will accept the consequences of failing to pass a value of the correct type, is up to you.)

How to deal with functions that require too many parameters?

You can use **kwargs in order to specify that your function can accept an arbitrary number of arguments. Although this means that you will be able to call the function by providing less arguments than what the Product requires - however any issue will be reported directly from the constructor.

def creat_product(self, **kwargs) -> Product:
return Product(**kwargs)

And you should be able to call it exactly as before:

self.create_product(a='a', b='b', ...)

Note that in this way, you would be able to call the function by providing a dictionary as an argument. For instance,

my_args = {'a': 'val1', 'b': 'val2', ...}
create_product(**my_args)

As a side note, I guess that create_product is an alternative constructor and thus it makes more sense to change it into a class method:

@classmethod
def creat_product(cls, **kwargs):
return cls(**kwargs)

In Python, is it possible to restrict the type of a function parameter to two possible types?

The term you're looking for is a union type.

from typing import Union

def f(parameter: Union[int, list]):
...

Union is not limited to two types. If you ever have a value which is one of several known types, but you can't necessarily know which one, you can use Union[...] to encapsulate that information.

How to specify input function parameter type and return type when passing the function as an argument to another function?

You can use typing.Callable:

from typing import Callable

def bar(b: str, func: Callable[[str], int])->int:
return func(b)

How do I pass a variable by reference?

Arguments are passed by assignment. The rationale behind this is twofold:

  1. the parameter passed in is actually a reference to an object (but the reference is passed by value)
  2. some data types are mutable, but others aren't

So:

  • If you pass a mutable object into a method, the method gets a reference to that same object and you can mutate it to your heart's delight, but if you rebind the reference in the method, the outer scope will know nothing about it, and after you're done, the outer reference will still point at the original object.

  • If you pass an immutable object to a method, you still can't rebind the outer reference, and you can't even mutate the object.

To make it even more clear, let's have some examples.

List - a mutable type

Let's try to modify the list that was passed to a method:

def try_to_change_list_contents(the_list):
print('got', the_list)
the_list.append('four')
print('changed to', the_list)

outer_list = ['one', 'two', 'three']

print('before, outer_list =', outer_list)
try_to_change_list_contents(outer_list)
print('after, outer_list =', outer_list)

Output:

before, outer_list = ['one', 'two', 'three']
got ['one', 'two', 'three']
changed to ['one', 'two', 'three', 'four']
after, outer_list = ['one', 'two', 'three', 'four']

Since the parameter passed in is a reference to outer_list, not a copy of it, we can use the mutating list methods to change it and have the changes reflected in the outer scope.

Now let's see what happens when we try to change the reference that was passed in as a parameter:

def try_to_change_list_reference(the_list):
print('got', the_list)
the_list = ['and', 'we', 'can', 'not', 'lie']
print('set to', the_list)

outer_list = ['we', 'like', 'proper', 'English']

print('before, outer_list =', outer_list)
try_to_change_list_reference(outer_list)
print('after, outer_list =', outer_list)

Output:

before, outer_list = ['we', 'like', 'proper', 'English']
got ['we', 'like', 'proper', 'English']
set to ['and', 'we', 'can', 'not', 'lie']
after, outer_list = ['we', 'like', 'proper', 'English']

Since the the_list parameter was passed by value, assigning a new list to it had no effect that the code outside the method could see. The the_list was a copy of the outer_list reference, and we had the_list point to a new list, but there was no way to change where outer_list pointed.

String - an immutable type

It's immutable, so there's nothing we can do to change the contents of the string

Now, let's try to change the reference

def try_to_change_string_reference(the_string):
print('got', the_string)
the_string = 'In a kingdom by the sea'
print('set to', the_string)

outer_string = 'It was many and many a year ago'

print('before, outer_string =', outer_string)
try_to_change_string_reference(outer_string)
print('after, outer_string =', outer_string)

Output:

before, outer_string = It was many and many a year ago
got It was many and many a year ago
set to In a kingdom by the sea
after, outer_string = It was many and many a year ago

Again, since the the_string parameter was passed by value, assigning a new string to it had no effect that the code outside the method could see. The the_string was a copy of the outer_string reference, and we had the_string point to a new string, but there was no way to change where outer_string pointed.

I hope this clears things up a little.

EDIT: It's been noted that this doesn't answer the question that @David originally asked, "Is there something I can do to pass the variable by actual reference?". Let's work on that.

How do we get around this?

As @Andrea's answer shows, you could return the new value. This doesn't change the way things are passed in, but does let you get the information you want back out:

def return_a_whole_new_string(the_string):
new_string = something_to_do_with_the_old_string(the_string)
return new_string

# then you could call it like
my_string = return_a_whole_new_string(my_string)

If you really wanted to avoid using a return value, you could create a class to hold your value and pass it into the function or use an existing class, like a list:

def use_a_wrapper_to_simulate_pass_by_reference(stuff_to_change):
new_string = something_to_do_with_the_old_string(stuff_to_change[0])
stuff_to_change[0] = new_string

# then you could call it like
wrapper = [my_string]
use_a_wrapper_to_simulate_pass_by_reference(wrapper)

do_something_with(wrapper[0])

Although this seems a little cumbersome.

how to convert while loop into a function or procedure and pass in new parameters python

Frankly, it would be better to get some tutorial to learn basis like functions.

def my_function(price):
while price > 1000:
price = price * 0.9
print("£", price)

and don't forget to run it

my_function(Motorbike_price)


Related Topics



Leave a reply



Submit