Is it possible to dynamically add arguments to a Python method definition ?
I'm currently working on this piece of code:
def method(self):
pass
method.__name__ = "print"
and I want to know if it's possible to change the method's definition dynamically, like i'm changing it's name, and for example add a string argument ?
Related
I am transitioning from Java to Python and am currently stumped with this seemingly simple code whose Java equivalent works just fine.
I am trying to create an object called TestClass that either takes one argument called text or no arguments; in which case a default string "foo" is assigned to the text instance variable.
class TestClass(object):
def __init__(self):
self.text = "foo"
def __init__(self, text):
self.text = text
a = TestClass()
b = TestClass("bar")
I really am unable to pinpoint the issue and get the following error:
a = TestClass()
TypeError: init() missing 1 required positional argument: 'text
Your help would be appreciated, Thank you!
Java doesn't have default values for parameters (last time I checked at least)
In Python, you cannot override methods with different parameters (well it's possible, but the first definition becomes invisible so that's not very useful).
So what you're trying to do translates like this:
def __init__(self, text="foo"):
self.text = text
That's okay with strings, integers, floats, but be careful with mutable types though: "Least Astonishment" and the Mutable Default Argument
Also, if you want to "emulate" same method name with different argument types, you have to define one method (that doesn't change) and use dynamic type checking to decide what to do:
def __init__(self, param):
if isinstance(param,str):
# param is a string
elif isinstance(param,int):
# param is an integer
This is a little bit weird. I want to dynamic initialize part of function's parameters before I call it. But I don't want to use class for some reason. Let's say I have a function:
def inner(a,b,c):
"a,b,c do something"
return result
Before I formally call it, I'd like to initialize it somewhere:
partInitalAbc=inner(,b,c)
Then I'll use it as:
result=partInitialAbc(a)
Please notice I want to do this dynamically. Just as when you initial a class using the constructor, so a decorator may be not appropriate at this time...
Any one have some idea?
It sounds like you're looking for functools.partial:
Return a new partial object which when called will behave like func called with the positional arguments args and keyword arguments keywords.
If you pass the arguments to partial as positional arguments, they'll appear at the beginning of the argument list, which isn't exactly what you want. Keyword arguments give you more control over which parameters are passed:
partInitialAbc = functools.partial(inner, b=b_value, c=c_value);
This question already has answers here:
Why does setattr fail on a bound method
(2 answers)
Closed 9 years ago.
I'm wondering if it is possible to use setattr to set an attribute to a method within a class like so because when I try I get an error which is going to be shown after the code:
class Test:
def getString(self, var):
setattr(self.getString, "string", var)
return self.getString
test = Test()
test.getString("myString").string
Which errors AttributeError: 'method' object has no attribute 'string' so I tried it without putting .string and just tried test.getString("myString") Same error, but then I tried it without the using the class just like this
def getString(var):
setattr(getString, "string", var)
return getString
getString("myString").string
It returned "myString" like I wanted it to, so how would I do this within a class and why does it work outside of one but inside of one?
type( test.getString ) is builtins.method and from the documentations ( methods ),
since method attributes are actually stored on the underlying function
object (meth.__func__), setting method attributes on bound methods is
disallowed. Attempting to set an attribute on a method results in an
AttributeError being raised.
There are (at least) two possible solutions depending on which behaviour you are looking for. One is to set the attribute on the class method:
class Test:
def getString(self, var):
setattr(Test.getString, "string", var)
return self.getString
test = Test()
test.getString("myString").string # > "myString"
test2 = Test()
test2.getString.string # > this is also "myString"
and the other is to use function objects:
class Test:
class getStringClass:
def __call__ ( self, var ):
setattr( self, "string", var )
return self
def __init__( self ):
self.getString = Test.getStringClass( )
test = Test( )
test.getString( "myString" ).string # > "myString"
test2 = Test()
test2.getString.string # > this is error, because it does not
# have the attribute 'string' yet
Functions are like most other objects in that you can freely add attributes to them. Methods, on the other hand... conceptually they're just functions, but they behave slightly differently (implicity pass self) and therefore are implemented with a bit of extra glue around functions.
Every time self.getString is evaluated, a new (bound) method object is created, which is a thin wrapper around the underlying function (which you can access as Test.getString). These method objects don't allow adding attributes, and even if they did, your code would not work because it juggles multiple distinct method objects (though they all wrap the same function).
You can't make this work with bound methods. Since you presumably want the string to be attached to the Test object (indirectly, by being attached to its method), you can make it an attribute of Test. You could even create your own object that behaves like a method but allows attributes (you'd have to explicitly add it in __init__), but honestly there's probably a better way that keeps data and methods separated. If, on the other hand, you want to attach this attribute to the underlying function (which would mean it's shared by all Test instances), you can just set the attribute on Test.getString.
So, I found a way but it's not really how I wanted to do it personally. If anyone does find another way to do the following code feel free to comment on how to do it.
class Test:
def getString(self, string):
setattr(self,"newString",self)
self.newString.string = string
return self.newString
Like I said, I don't feel like I accomplished anything by doing it that way, but it works for what I need and if you do find another way comment below.
i have a function that retrieve a list of stores in Python this functions is called :
class LeclercScraper(BaseScraper):
"""
This class allows scraping of Leclerc Drive website. It is the entry point for dataretrieval.
"""
def __init__(self):
LeclercDatabaseHelper = LeclercParser
super(LeclercScraper, self).__init__('http://www.leclercdrive.fr/', LeclercCrawler, LeclercParser, LeclercDatabaseHelper)
def get_list_stores(self, code):
"""
This method gets a list of stores given an area code
Input :
- code (string): from '01' to '95'
Output :
- stores :
[{
'name': '...',
'url'
}]
"""
when i try to write get_list_stores(92) i get this error :
get_list_stores(92)
TypeError: get_list_stores() takes exactly 2 arguments (1 given)
how can you help me with this ?
If the function is inside a class (a method), write it like this:
def get_list_stores(self, code):
And you have to call it over an instance of the class:
ls = LeclercScraper()
ls.get_list_stores(92)
If it's outside a class, write it without the self parameter:
def get_list_stores(code):
Now it can be called as a normal function (notice that we're not calling the function over an instance, and it's no longer a method):
get_list_stores(92)
You don't use "self" arbitrarily - self is recommended to be the first parameter to functions which are written to be methods in classes. In that case, when it is invoked as a method, like in
class A(object):
def get_list_stores(self, code):
...
a = A()
a.get_listscores(92)
Python will insert the "self" parameter automatically on the call
(and it will be the object named "a" in the outer scope)
Outside of class definitions, having a first parameter named "self" does not make
much sense - although, as it is not a keyword it is not an error per se.
In your case, most likely,t he function you are trying to call is defined in class:
you have to call it as an attribute of an instance of the class, and then you
simply omit the first parameter - just like in the example above.
If you are trying to use it in the class, access it like this:
self.get_listscores(92)
If you are trying to access it outside of the class, you need to first create an instance of LeclercScraper:
x = LeclercScraper()
y = x.get_listscores(92)
Also, self is not a keyword. It is simply the name chosen by convention to represent a class instance within itself.
Here's a good reference:
What is the purpose of self?
So I am trying out the new python code for the google app engine search library and I came across a weird syntax. This was:
cls_createDocument(**params)
where params was a dictionary.
The function this refers to is:
#classmethod
def _createDocument(
cls, pid=None, category=None, name=None, description=None,
category_name=None, price=None, **params)
My questions is, what does the **params signify and what does that do to the object?
Thanks!
Jon
Consider a function with default arguments:
def func(foo=3):
print(foo)
The structure of the arguments is (in principle) very similar to a dictionary. The function foo has (essentially) a dictionary of default arguments (in this case {'foo':3}). Now, lets say that you don't want to use the keyword in the function call, but you want to use a dictionary instead -- then you can call foo as:
d = {"foo":8}
func(**d)
This allows you to dynamically change what arguments you are passing to the function func.
This become a little more interesting if you try the following:
d = {"foo":8, "bar":12}
func(**d)
This doesn't work (it is equivalent to foo(foo=8, bar=12), but since bar isn't a valid argument, it fails).
You can get around that problem by giving those extra arguments a place to go inside the definition of foo.
def func( foo=3, **kwargs ):
print(foo,kwargs)
Now, try:
d = {"foo":8, "bar":12}
func(**d) #prints (8, {'bar':12})
All the extra keyword arguments go into the kwargs dictionary inside the function.
This can also be called as:
func(foo=8, bar=12)
with the same result.
This is often useful if funcA calls funcB and you want funcA to accept all of the keywords of funcB (plus a few extra) which is a very common thing when dealing with classes and inheritance:
def funcA(newkey=None,**kwargs):
funcB(**kwargs)
Finally, here is a link to the documentation
The **params parameter represents all the keyword arguments passed to the function as a dictionary.