How to change string object location to an object

2019-07-30 06:07发布

问题:

I need to convert string object location to an object. My code is:

class Dog:
    def __init__(self,name):
        self.name= name

    def bark(self):
        print('BAR')

b=''

a=Dog('Test')
print(a)
with open('Dog.txt','w') as file:
   file.write(str(a))

with open('Dog.txt','r') as file:
   b=file.read()
   b=repr(b)

print(b)
b.bark()

I saved the object a in a Dog.txt file <__main__.Dog object at 0x0000024E1C7AFE80> and now i want to take that string and convert it to an object so I can use the bark method with it.

How can I do this

回答1:

you can use PyYAML:

pip install PYyaml

and dump and load data from yaml files:

In [1]: class Dog:
   ...:     def __init__(self,name):
   ...:         self.name= name
   ...: 
   ...:     def bark(self):
   ...:         print('BAR')
   ...: 
   ...: b=''
   ...: 
   ...: a=Dog('Test')
   ...: print(a)
   ...: 
   ...: 
<__main__.Dog object at 0x7fb082811390>

now dump you object to the yaml:

In [2]: import yaml

In [3]: with open('data.yml', 'w') as outfile:
   ...:     yaml.dump(a, outfile, default_flow_style=False)

inside the data.yml you will see:

!!python/object:__main__.Dog
name: Test

and now load:

In [6]: with open('data.yml', 'r') as loadfile:
   ...:     data = yaml.load_all(loadfile)
   ...:     b = next(data)
   ...:     

In [7]: b
Out[7]: <__main__.Dog at 0x7fb07bfd5f28>

In [8]: b.bark()
BAR


回答2:

You cannot recover an object from its string representation. You should instead serialize the object before dumping it to the file. You can use pickle for this

>>> a
<__main__.Dog object at 0x7f6d4ee8fb38>
>>> 
>>> pickle.dump(a, open('Dog.txt', 'wb'))
>>> b = pickle.load(open('Dog.txt', 'rb'))
>>> b
<__main__.Dog object at 0x7f6d4ee8fac8>
>>> b.bark()
BAR


回答3:

Both Bear Brown and Sunitha fail to mention that the loading they propose to do can be unsafe. For PyYAML this is clearly indicated at the start of the tutorial:

Warning: It is not safe to call yaml.load with any data received from an untrusted source! yaml.load is as powerful as pickle.load and so may call any Python function

Pickle has a similar warning:

Warning The pickle module is not secure against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source

At least using YAML, it is not necessary to run any risks now or in the future.

First do:

pip install ruamel.yaml

Then:

from ruamel.yaml import YAML

class Dog:
    # yaml_tag = u'!Doggie'
    def __init__(self, name):
        self.name = name

    def bark(self):
        print('BARK')

b = ''

a = Dog('Test')

yaml = YAML(typ='safe')
yaml.register_class(Dog)

with open('Dog.yaml','w') as ofp:
   yaml.dump(a, ofp)

with open('Dog.yaml') as ifp:
   b = yaml.load(ifp)

print(b.name, b)
b.bark()

print('==========')
with open('Dog.yaml') as ifp:
    print(ifp.read(), end='')

which gives:

Test <__main__.Dog object at 0x7f88a5479320>
BARK
==========
!Dog {name: Test}

Notes:

  • The "official" FAQ on yaml.org asks to use .yaml as the file extension for files containing YAML.
  • You can uncomment the "yaml_tag =" line, to use a different tag in YAML document than the default (i.e. your class name)
  • Not only is this safe, it also doesn't have __main__ in the YAML file, which is essential if you ever decide to move the class definition to a different file.
  • Although not as fast as using pickle, the above is much (~10x) faster than the solution Bear Brown proposes. That might be relevant if you have 101 Dalmatians to dump and load.
  • It is not noticeable in your example data, but the above loads/dumps YAML according to the YAML 1.2 specification (published 2009) and also supports the long outdated YAML 1.1 specification. PyYAML has never been updated and still only supports YAML 1.1.

(Disclaimer: I am the author of ruamel.yaml)